package com.merry.beanFactory.bf;

import java.util.Set;

import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.config.NamedBeanHolder;
import org.springframework.lang.Nullable;

/**
 * AutowireCapableBeanFactory：有能力进行自动装配的BeanFactory。
 *
 *  扩展{@link BeanFactory}接口，由 {capable of autowiring beanFactory} 实现，前提是它们想为现有的bean实例公开此功能。
 *
 */
public interface AutowireCapableBeanFactory extends BeanFactory {

    /**
     * 自动装配的常量定义，表示不进行自动装配。
     */
    int AUTOWIRE_NO = 0;

    /**
     * 表示按照名字进行自动装配。
     */
    int AUTOWIRE_BY_NAME = 1;

    /**
     * 表示按照类型进行自动装配。
     */
    int AUTOWIRE_BY_TYPE = 2;

    /**
     * 表示按照构造器类型进行自动装配。
     */
    int AUTOWIRE_CONSTRUCTOR = 3;

    /**
     * 已弃用。
     */
    @Deprecated
    int AUTOWIRE_AUTODETECT = 4;

    /**
     * beanName的后缀。
     */
    String ORIGINAL_INSTANCE_SUFFIX = ".ORIGINAL";


    //-------------------------------------------------------------------------
    // 创建和填充外部bean实例的典型方法
    //-------------------------------------------------------------------------

    /**
     * 创建bean实例的方法。（眼熟，在源码中会调用 doCreateBean 方法完成bean的新增）。
     *  执行bean的完整初始化，包括所有适用的 {@link BeanPostProcessor BeanPostProcessors}。
     *  注意：这是为了创建一个新的实例，填充带注释的字段和方法，以及应用所有标准的bean初始化回调。
     *  它并不意味着传统的通过名称或类型自动连接属性；为此，请使用{@link #createBean(Class,int,boolean)} 方法。
     */
    <T> T createBean(Class<T> beanClass) throws BeansException;

    /**
     * 根据入参完成自动装配。
     */
    void autowireBean(Object existingBean) throws BeansException;

    /**
     * 配置给定的原始bean。
     */
    Object configureBean(Object existingBean, String beanName) throws BeansException;


    //-------------------------------------------------------------------------
    // 对bean生命周期进行细粒度控制的专门方法，这就是我们背的八股文方法源码。
    //-------------------------------------------------------------------------

    /**
     * 创建bean，会完成bean的整个生命周期。在源码中会调用 doCreateBean 完成创建。
     */
    Object createBean(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;

    /**
     * 使用指定的autowire策略实例化给定类的新bean实例。
     */
    Object autowire(Class<?> beanClass, int autowireMode, boolean dependencyCheck) throws BeansException;

    /**
     * 使用指定的autowire策略实例化给定类的新bean实例
     */
    void autowireBeanProperties(Object existingBean, int autowireMode, boolean dependencyCheck)
            throws BeansException;

    /**
     *
     */
    void applyBeanPropertyValues(Object existingBean, String beanName) throws BeansException;

    /**
     * 会在创建完bean实例之后调用。
     */
    Object initializeBean(Object existingBean, String beanName) throws BeansException;

    /**
     * beanPostProcessor 的前置方法，会在刚刚创建bean之后调用。
     */
    Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
            throws BeansException;

    /**
     * beanPostProcessor的后置方法。
     */
    Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
            throws BeansException;

    /**
     * 销毁bean的方法，
     */
    void destroyBean(Object existingBean);


    //-------------------------------------------------------------------------
    // 解决注入的方法。
    //-------------------------------------------------------------------------

    /**
     * 解决依赖的方法。
     */
    <T> NamedBeanHolder<T> resolveNamedBean(Class<T> requiredType) throws BeansException;

    /**
     * 解决依赖的方法。
     */
    Object resolveBeanByName(String name, DependencyDescriptor descriptor) throws BeansException;

    /**
     * 解决依赖的方法。
     */
    @Nullable
    Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException;

    /**
     * 解决依赖的方法。
     */
    @Nullable
    Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
                             @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException;

}

